using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity.DataModel;

namespace T.FAS.Runtime.DataAccess.Common
{
    /// <summary>
    /// DQ扩展方法
    /// </summary>
    public static class DQCommonExtension
    {
        /// <summary>
        /// 获取当前CNO节点关联父级CNO的元素Element
        /// </summary>
        /// <param name="cno"></param>
        /// <returns></returns>
        public static DatabaseType GetDQDatabase(this DataQuery metadata)
        {
            try
            {
                string dbType = metadata.DataQuerySources.Find(s => s.IsMainSource).DataObject.Database.DbType;
                return (DatabaseType)Enum.Parse(typeof(DatabaseType), dbType);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Metadata.DQ.MetadataError, string.Format(CommonStringClassCommon.DQCommonExtension_GetDQDatabase,metadata?.Code), e);
            }
        }

        /// <summary>
        /// DQ是否包含列权限控制
        /// </summary>
        /// <param name="dq"></param>
        /// <returns></returns>
        public static bool IsHaveColumnPermission(this DataQuery dq)
        {
            bool isHaveColumnPermission = false;
            if (dq == null)
                return isHaveColumnPermission;
            try
            {
                List<DataObject> dataObjects = new List<DataObject>();
                foreach (var source in dq.DataQuerySources)
                {
                    if (source.DataObject != null && source.DataObject.IsHaveColumnPermission())
                        dataObjects.Add(source.DataObject);
                }
                isHaveColumnPermission = dataObjects.Count > 0;
            }
            catch (Exception e)
            {
            }
            return isHaveColumnPermission;
        }

        #region SubQuery
        /// <summary>
        /// 获取子查询的主查询列
        /// </summary>
        /// <param name="parentQuery"></param>
        /// <param name="subQuery"></param>
        /// <returns></returns>
        public static DataQueryColumn GetMainQueryColumn(this DataQuery parentQuery, DataQuerySubQuery subQuery)
        {
            return parentQuery.DataQueryColumns?.FirstOrDefault(col => col.ID == subQuery.MainQueryColumnID);
        }

        public static DataQueryColumn GetSubQueryColumn(this DataQuery childQuery, DataQuerySubQuery subQuery)
        {
            var subQueryRelatedColumn = childQuery.DataQueryColumns?.FirstOrDefault(col => col.ID == subQuery.SubQueryColumnID);
            if (subQueryRelatedColumn == null)
            {
                var errorCode = $"元数据DataQuery，ID:{subQuery.DataQueryID}的子查询:id:{subQuery.SubQueryID},alias:{subQuery.SubQueryAlias}的列集合中不包含关联列:{subQuery.SubQueryColumnID}";
                throw new FasException(DataAccessErrorCode.DataQuery.Error, errorCode);
            }
            return subQueryRelatedColumn;
        }

        public static DataQuerySource GetMainQuerySource(this DataQuery parentQuery, DataQuerySubQuery subQuery)
        {
            var queryCol = parentQuery.GetMainQueryColumn(subQuery);
            return parentQuery.DataQuerySources.FirstOrDefault(s => s.ID == queryCol.DataQuerySourceID);
        }

        public static DataQuerySource GetSubQuerySource(this DataQuery childQuery, DataQuerySubQuery subQuery)
        {
            var queryCol = childQuery.GetSubQueryColumn(subQuery);
            return childQuery.DataQuerySources.FirstOrDefault(s => s.ID == queryCol.DataQuerySourceID);
        }
        #endregion

        #region Param
        /// <summary>
        /// 替换使用变量的语句
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string ProcessUsingParamString(this DataQuery dataQuery, string text, Func<string, string> func)
        {
            if (string.IsNullOrEmpty(text))
                return text;
            var patternTmp = "(?<!\\w)@{0}(?!\\w)";
            foreach (var param in dataQuery.DataQueryParams)
            {
                if (param.Code == DACConst.DQ.AdvancedFilterString) continue;
                var newParamKey = func(param.Code);
                var pattern = string.Format(patternTmp, param.Code);
                text = Regex.Replace(text, pattern, $"@{newParamKey}");
            }
            return text;
        }

        /// <summary>
        /// 替换使用变量的语句
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string ProcessUsingParamStringWithPrefix(this DataQuery dataQuery, string text, string paramPrefix)
        {
            var result = dataQuery.ProcessUsingParamString(text, (param) => paramPrefix + param);
            return result;
        }

        /// <summary>
        /// 将可能用到变量的地方，全部加入变量前缀，最后替换DQ.Param本身
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static void ProcessDataQueryWithParamPrefix(this DataQuery dataQuery, string paramPrefix)
        {
            Func<string, string> func = (param) => paramPrefix + param;

            var columns = dataQuery.DataQueryColumns?.Where(col => col.ColumnType == ColumnType.Express).ToList();
            if (columns != null && columns.Count > 0)
            {
                foreach (var col in columns)
                {
                    col.ColumnExpression = dataQuery.ProcessUsingParamStringWithPrefix(col.ColumnExpression, paramPrefix);
                    col.ColumnExpressionJson = dataQuery.ProcessUsingParamStringWithPrefix(col.ColumnExpressionJson, paramPrefix);
                }
            }

            var joins = dataQuery.DataQueryJoins?.ToList();
            if (joins != null && joins.Count > 0)
            {
                foreach (var join in joins)
                {
                    join.JoinExpression = dataQuery.ProcessUsingParamStringWithPrefix(join.JoinExpression, paramPrefix);
                    join.JoinExpressionJson = dataQuery.ProcessUsingParamStringWithPrefix(join.JoinExpressionJson, paramPrefix);
                }
            }

            var filters = dataQuery.DataQueryFilters?.ToList();
            if (filters != null && filters.Count > 0)
            {
                foreach (var filter in filters)
                {
                    filter.FilterExpression = dataQuery.ProcessUsingParamStringWithPrefix(filter.FilterExpression, paramPrefix);
                    filter.FilterExpressionJson = dataQuery.ProcessUsingParamStringWithPrefix(filter.FilterExpressionJson, paramPrefix);
                }
            }

            var sorts = dataQuery.DataQuerySorts?.Where(sort => sort.SortItemType == 1).ToList();
            if (sorts != null && sorts.Count > 0)
            {
                foreach (var sort in sorts)
                {
                    sort.SortExpression = dataQuery.ProcessUsingParamStringWithPrefix(sort.SortExpression, paramPrefix);
                    sort.SortExpressionJson = dataQuery.ProcessUsingParamStringWithPrefix(sort.SortExpressionJson, paramPrefix);
                }
            }

            var @params = dataQuery.DataQueryParams?.ToList();
            if (@params != null && @params.Count > 0)
            {
                foreach (var par in @params)
                {
                    par.Code = func(par.Code);
                }
            }
        }

        /// <summary>
        /// 将参数字典中的Key都替换为带前缀版本
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="paramList"></param>
        /// <param name="paramPrefix"></param>
        public static void ProcessParamDictListWithParamPrefix(this DataQuery dataQuery, ref Dictionary<string, object> paramList, string paramPrefix)
        {
            Func<string, string> func = (param) => paramPrefix + param;
            if (dataQuery.DataQueryParams != null && dataQuery.DataQueryParams.Count > 0)
            {
                var paramCodes = dataQuery.DataQueryParams.Select(p => p.Code).ToList();
                var newParamList = new Dictionary<string, object>();

                foreach (var key in paramList.Keys)
                {
                    if (paramCodes.Contains(key))
                    {
                        newParamList[func(key)] = paramList[key];
                    }
                    else
                    {
                        newParamList[key] = paramList[key];
                    }
                }
                paramList = newParamList;
            }
        }
        #endregion
    }
}
